/* Includes ------------------------------------------------------------------*/
#include "MyApplication.h"

/* Private define-------------------------------------------------------------*/
#define FUNCTIONCODE_READ_REGISTER  0x03
#define FUNCTIONCODE_WRITE_REGISTER 0x06
#define MODBUS_ORDER_LENGTH         8
/* Private variables----------------------------------------------------------*/
static void Protocol_Analysis(UART_t* );
static void Modbus_Read_Register(UART_t* );
static void Modbus_Write_Register(UART_t* );
/* Public variables-----------------------------------------------------------*/
Modbus_t Modbus = 
{
  1,
  Protocol_Analysis
};
/* Private function prototypes------------------------------------------------*/

/*
* @name   Protocol_Analysis
* @brief  Modbus协议分析
* @param  UART：串口类型的指针
* @retval None   
*/
static void Protocol_Analysis(UART_t* UART)
{
  UART_t * const COM = UART;
  uint8_t i,index = 0;
  //先关闭串口3的DMA接收，再作数据处理
  HAL_UART_DMAStop(&huart3);

  //过滤干扰数据，首字节为从机地址，共8个字节
  for(i=0;i<PUCUART3_REC_BUFFER_LEN;i++)
  {
    //判断下标index是否为0
    if(index == 0)
    {
      /*如果接收数组的前面数据不是从机地址，则跳过本次循环,
      循环体内后面的代码也不会执行，没有执行continue则执行
      后面*/
      if(*(COM->pucRec_Buffer+i) != Modbus.Addr){continue;}
    }
    //执行到这里，说明没有执行continue语句，找到了从机地址，则保存数据
    *(COM->pucRec_Buffer+index) = *(COM->pucRec_Buffer+i);
    //当下标为8时，说明已经读取7个字节，退出循环
    if(index == MODBUS_ORDER_LENGTH)
    {
      break;
    }
    //下标加一，再循环时则不会去找从机地址
    index++;
  }

  //处理数据
  //计算CRC校验值
  CRC_16.CRC_Value =  CRC_16.CRC_Check(COM->pucRec_Buffer,6);
  CRC_16.CRC_H = CRC_16.CRC_Value >> 8;   //取出CRC校验值高位
  CRC_16.CRC_L = CRC_16.CRC_Value;        //取出CRC校验值低位

  //校验CRC
  if(((*(COM->pucRec_Buffer+6) == CRC_16.CRC_H) && (*(COM->pucRec_Buffer+7) == CRC_16.CRC_L)) ||
  ((*(COM->pucRec_Buffer+6) == CRC_16.CRC_L) && (*(COM->pucRec_Buffer+7) == CRC_16.CRC_H)))
  {
    //校验地址
    if(*(COM->pucRec_Buffer+0) == Modbus.Addr)
    {
      //判断功能码
      //读单个或多个寄存器
      if(*(COM->pucRec_Buffer+1) == FUNCTIONCODE_READ_REGISTER)
      {
        Modbus_Read_Register(COM);
      }
      //写单个寄存器
      else if(*(COM->pucRec_Buffer+1) == FUNCTIONCODE_WRITE_REGISTER)
      {
        Modbus_Write_Register(COM);
      }
    }
  }

  //清理缓存
  for(i=0;i<PUCUART3_REC_BUFFER_LEN;i++)
  {
    *(COM->pucRec_Buffer+i) = 0x00;
  }
}

/*
* @name   Modbus_Read_Register
* @brief  读寄存器
* @param  UART：串口类型的指针
* @retval void   
*/
static void Modbus_Read_Register(UART_t* UART)
{
  UART_t* const COM = UART;
  //判断读取地址（40001 ->  0x9C41）
  if((*(COM->pucRec_Buffer+2) == 0x9C) && (*(COM->pucRec_Buffer+3) == 0x41))
  {
    //回应数据
    //地址码
    *(COM->pucSend_Buffer+0) = Modbus.Addr;
    //功能码
    *(COM->pucSend_Buffer+1) = FUNCTIONCODE_READ_REGISTER;
    //数据长度
    *(COM->pucSend_Buffer+2) = 8;
    //SHT30温度
    *(COM->pucSend_Buffer+3) = ((uint16_t)((SHT30.fTemperature+40)*10))/256;
    *(COM->pucSend_Buffer+4) = ((uint16_t)((SHT30.fTemperature+40)*10))%256;
    //SHT30湿度
    *(COM->pucSend_Buffer+5) = 0;
    *(COM->pucSend_Buffer+6) = SHT30.ucHumidity;
    //继电器状态
    *(COM->pucSend_Buffer+7) = 0;
    *(COM->pucSend_Buffer+8) = Relay.Relay_Status;
    //蜂鸣器状态 
    *(COM->pucSend_Buffer+9)  = 0;
    *(COM->pucSend_Buffer+10) = Buzzer.Status;

    //计算CRC校验值
    CRC_16.CRC_Value = CRC_16.CRC_Check(COM->pucSend_Buffer,11);
    
    //得到CRC校验值高低位
    CRC_16.CRC_H = CRC_16.CRC_Value >> 8;
    CRC_16.CRC_L = CRC_16.CRC_Value;
		
    //CRC校验值
    *(COM->pucSend_Buffer+11) = CRC_16.CRC_L;
    *(COM->pucSend_Buffer+12) = CRC_16.CRC_H;
    
    //发送数据
    UART3.SendArray(COM->pucSend_Buffer,13);
		
  }
}


/*
* @name   Modbus_Write_Register
* @brief  写寄存器
* @param  UART：串口类型的指针
* @retval void   
*/
static void Modbus_Write_Register(UART_t* UART)
{
  UART_t* const COM = UART;
  uint8_t i;
  //返回数据，与上位机发来的数据一样
  for(i=0;i<8;i++)
  {
    *(COM->pucSend_Buffer+i) = *(COM->pucRec_Buffer+i);
  }

  //发送数据
  UART3.SendArray(COM->pucSend_Buffer,8);
  //取数据
  //判断寄存器地址
  if((*(COM->pucRec_Buffer+2) == 0x9C) && (*(COM->pucRec_Buffer+3) == 0x43))
  {
    //控制继电器状态
    if(*(COM->pucRec_Buffer+5) == 0x01)
    {
      //吸合继电器
      Relay.Relay_ON();
    }
    else
    {
      //断开继电器
      Relay.Relay_OFF();
    }
  }

  if((*(COM->pucRec_Buffer+2) == 0x9C) && (*(COM->pucRec_Buffer+3) == 0x44))
  {
    //控制蜂鸣器状态
    if(*(COM->pucRec_Buffer+5) == 0x01)
    {
      //打开蜂鸣器
      Buzzer.Buzzer_ON();
    }
    else
    {
      //关闭蜂鸣器
      Buzzer.Buzzer_OFF();
    }
  }
}
/********************************************************
  End Of File
********************************************************/
